Conversation
Closes: #53, #48, #56 Upgraded Quasar and Vue, added Pinia integration. Moved all encounter logic to dedicated Pinia store and simplified some business logic. Adapted tables and objects to new AoN JSON dump obtainable directly from their website. Added new menu buttons for support, donation and release info (to be reviewed further).
…Vue Devtools at launch
Allows developing and deploying the app under a subfolder by reading the base path from an environment variable. This enables hosting on GitHub Pages and having two versions coexist simultaneously before promoting to the root.
Adjusted `$primary` and `$secondary` color values in Quasar variables to align with project colors.
…eatures Adjusted logic for level modifications, fixes #57
…g to match Webstorm configs
…rated to dedicated repository Deleted unused scraper module, including associated configuration, dependencies, and source files, to clean up the codebase.
…ated to pnpm Since the deletion of the webscraper (moved to separate repo), moved the quasar spa code to the root level.
…ed caching Replaced `/table-data_stripped.json` with `/creatures.json` to load the correct data source.
…ogic We no longer compute metadata values on the client but the app is provided with a metadata.json containing all of them. Removed `indexedProperties` and related compute methods. Added metadata fetching to streamline handling of creature metadata like sizes and traits. Enhanced getters for improved state access.
Deleted `example-store.js` as it was unused.
… improving utility functions Added meaningful comments to document getters and actions. Refactored `computeDeltaCost` to use a cleaner mapping approach for predefined deltas.
Introduced `$reset` method to reset the encounter state, clearing all creatures. Streamlines resetting functionality for encounters.
Deleted outdated `table-data_all.json` data source to clean up unnecessary artifacts and reduce redundancy.
… files Added `quasar.config.ts`, `tsconfig.json`, and updated project files for TypeScript support. Configured ESLint and Prettier to align with project standards.
…move page references and HTML tags
node_modules is centrally handled by pnpm through workspaces
…fetch The old fetcher drove a headless Chromium browser through the AoN Creatures.aspx UI (click "Load remaining", click "Export as JSON") to scrape data. It broke when AoN added a cookie-consent overlay and never captured NPCs, since the UI export only covers monsters. The new tools/aon-downloader/fetch-creatures.js queries AoN's public Elasticsearch endpoint directly: one HTTP request returns every monster and NPC (4665 total, 917 of them NPCs) with a richer schema (alignment, family, numeric level/hp/ac, array traits/size/sources). Zero dependencies, no browser binary. A 7-day freshness guard means routine dev/install runs never hit AoN's servers; refresh is explicit (--force) or via the new monthly scheduled workflow. Removes playwright, pino and the build-report.js companion script (metadata generation is now inline in the fetch script).
CreaturesTable: name search, monster/NPC toggle, level range slider, and a collapsible advanced filter panel (rarity, size, alignment, family, traits, source). Restores filters lost in the v2 rewrite (alignment, family) and adds searchable multi-select (FilterSelect.vue) for the long trait/source/family lists. EncounterList: was ~80% placeholder, now fully functional — weak/base /elite toggle per creature, count stepper, per-creature and total XP, clear-encounter action, AoN link per creature. ThreatBar: rebuilt as a CSS track/fill instead of manually positioned absolute badges; scale compresses instead of overflowing past the extreme budget. Fixes a latent Pinia reactivity bug (closes #17, milestone v2): IndexPage destructured store computeds directly off the setup-store (`const xpCost = encounterStore.xpCost`), freezing their value at mount instead of tracking party level/size changes. Everything now goes through storeToRefs. Also: license dialog renders real Paizo Community Use Policy text instead of a commented-out block (closes #68); header/menu links point at real destinations; removed dead code (unused axios boot, example-store, stub user-store, duplicate stores/index.js, debug console.log/CSS).
update-creatures.yml: scheduled job (1st of every month) runs the new fetch-creatures.js --force, commits refreshed public/creatures.json + metadata.json to both development and main, then triggers deploy. deploy.yml: builds the Quasar SPA and publishes dist/spa (data included) to the gh-pages branch on push to main. Removes GitHubPagesDeploymentWorkflow.yml and build-deploy.yaml — both yarn-based and targeting the old src/webui v1 layout, non-functional against this codebase.
Technical changelog entry covering the data pipeline rewrite, frontend completion, and CI changes, plus a list of known gaps not addressed in this release (issues #62, #43, #25, #52, #51, #18). RELEASE_NOTES.md: user-facing summary — creature/NPC counts before and after, the move to a single polite Elasticsearch request instead of browser automation, and the encounter-builder improvements.
Reintroduces the Umami integration main had (same website ID, same `encounter-add-creature` bounce-workaround event from #66), gated to production builds only via the existing ctx.prod pattern so local dev never sends real traffic. Since users continuously add/remove creatures with no "encounter finished" signal to hook, tracking is built around discrete mutation events (creature added, weak/base/elite variant changed) plus a debounced "encounter-snapshot" (party level/size, XP cost, threat) fired 8s after the last edit, with an immediate flush on tab-hide/ pagehide so closing right after a change isn't lost. All three call sites are centralized in encounter-store.ts, the single place that already mutates this state.
package.json productName/description were still the Quasar CLI
scaffold defaults ("Quasar App" / "A Quasar Project"), which is what
showed up as the browser tab title.
Also adds a Buy Me a Coffee button to the header.
GM Core's Creature XP table only defines costs from party level -4 to +4. computeDeltaCost silently clamped anything past that to the same edge value, so a level 1 party vs. a level 25 solo still read as merely "Extreme" instead of the effectively unwinnable fight it is. Per the issue owner's own resolution direction (no unofficial extrapolated formula, just make the cap visible): encounter-store now exports isDeltaOutOfBounds(), and EncounterList shows a warning icon + tooltip on any creature whose delta exceeds the table's range. The per-creature cost itself is unchanged — still RAW as written. Party-size XP budget scaling (GM Core "Different Party Sizes", pg. 76) was already correct — xpBudget already scales with partySize and the per-creature cost already factors in partyLevel via the delta. Fixes #62
Vue's whitespace-condense compiler strips a leading literal space at the start of an element's text content, so "Trivial" and "40" rendered back-to-back as "Trivial40". Using instead of a plain space survives the trim.
First automated test suite for the project. Two thin layers: - Vitest (src/stores/encounter-store.spec.ts): encodes GM Core's rules tables row by row — XP budget per party size, creature XP per level delta, weak/elite exceptions — plus store actions and the analytics event contract (debounced snapshot via fake timers). happy-dom environment since the store registers window/document listeners. - Playwright, chromium-only (e2e/encounter-builder.spec.ts): smoke coverage of browse -> filter -> add -> balance against the real dev server and real AoN data, with regression tests for #17 (XP reactivity) and #62 (out-of-bounds delta warning). Config pins channel:'chromium' (full browser, not chromium_headless_shell) to dodge a known Windows worker-close hang (microsoft/playwright#39753). ci.yml runs lint + both suites on pushes to development/v2 and PRs to main, uploading the Playwright report on failure. package.json: pnpm test now runs both suites; test:unit and test:e2e run them individually.
Four ADRs document the non-obvious decisions made this cycle so future contributors (this repo is public) don't have to reverse-engineer the why from commit history: - 0001: creature data via AoN's public Elasticsearch endpoint - 0002: monthly data refresh + GitHub Pages deploy - 0003: privacy-first analytics with self-hosted Umami - 0004: testing strategy — Vitest for rules logic, Playwright for E2E README rewritten for contributors: real tech stack table, setup instructions, script reference, a repository tour, and a "how it works"/contributing section pointing at the ADRs. Removed the stale README_old.md (pre-rewrite v1 instructions, Vue CLI commands that no longer apply). CHANGELOG.md Unreleased section updated to reflect the testing and docs additions.
Resolves the conflicts blocking PR #72 (v2 -> main). All five direct conflicts were main-only bugfixes/tooling changes to src/webui/ (the old Quasar 1 / Vue 2 app: NPC redirect fix, Umami analytics tweaks, semantic-release setup) — code with no v2 equivalent because v2 is a full rewrite that never carried src/webui/ forward. Resolution keeps v2's deletion; none of those fixes apply to an app that no longer exists. Two more main-only additions surfaced once src/webui/ conflicts were resolved (not flagged as direct conflicts, but git staged them from main automatically since v2 has nothing at those paths): - .releaserc.json (root): same semantic-release config as the src/webui one, just relocated there by git's rename heuristic. Versions off src/webui/package.json, which no longer exists. Removed for the same reason as the src/webui copy. - .github/workflows/build-deploy.yaml: the same stale yarn-based deploy workflow already removed from development's own history (targeting the now-nonexistent src/webui layout) — main kept an independent copy. Removed; superseded by deploy.yml/ci.yml/ update-creatures.yml. One main-only change is kept: LICENSE_AON.md carries a substantially more complete set of Paizo/OGL book notices on main (674 vs 283 lines) — a genuine content improvement, auto-merged cleanly with no conflict. Root LICENSE.md (GPLv3, main-only) merges in unchanged — no conflict, resolves the "port LICENSE.md" item from the original PR body.
Non-technical recap for the actual audience (DMs and players, not
developers): bigger creature database, automatic monthly updates,
better filters, the new out-of-bounds difficulty warning, and a
cleaner UI. No jargon — no mention of Elasticsearch, CI, or anything
implementation-specific.
Shown once automatically (localStorage flag, versioned so the next
major release can announce itself the same way) and always reachable
again from the v2 menu ("What's new"). Also repoints the menu's
"Release notes" link from the technical CHANGELOG.md to the
user-facing RELEASE_NOTES.md — a better fit for the same audience.
CreaturesTable switches to q-table's native virtual-scroll — same footprint (fixed height, no layout shift), scrolls to load more instead of paging, still shows the total filtered count. Found and fixed a real bug along the way: Vue 3.5.x silently breaks Quasar 2.18.2's QTable virtual-scroll (renders zero rows, no error — confirmed with an isolated repro outside this app's code). Pins vue to an exact 3.4.38, documented in ADR 0005 so a routine dependency bump doesn't reintroduce it invisibly.
Root cause of the reported multi-second scroll freeze: each row's QBadge x2 + QBtn + QTooltip were mounting/unmounting on every scroll tick. Replaced with plain HTML/CSS (.badge-outline spans, a native <button> with a title attribute) — same look, zero component overhead. Measured: worst single blocking task 256ms -> 88ms, total wall time for a rapid-scroll burst 19.8s -> 3.6s. Also dropped virtual-scroll entirely. It stopped being reliable across a long debugging session (worked, then silently rendered zero rows after restarts/HMR churn, reproduced even from a clean production build) — not something to ship on. All ~4,665 filtered rows now render at once inside a fixed-height, natively-scrollable table; no DOM virtualization, but the lightweight per-row markup keeps that cheap. Vue stays pinned to 3.4.38 regardless (still the known-good version). Details in ADR 0005.
Reverts the previous commit's mistake. Rendering all ~4665 rows at once (60k+ DOM nodes) was the actual cause of the reported Firefox freeze — not virtual-scroll. The earlier "virtual-scroll renders zero rows" diagnosis was a false signal from the headless automation browser used for verification: it measures the scroll viewport a frame too early, computes an empty visible slice, and never recomputes without a resize/scroll event. Real browsers settle layout on first paint and render correctly. Confirmed by a user observing rows fine in Firefox while the automation browser showed none until a forced resize. Restores `virtual-scroll` (~60 rows in the DOM at a time). Drops the markRaw() on the rows array — tested, it was never the cause. Keeps the plain-HTML badges/button (a real per-row weight reduction). Deletes ADR 0005: its whole premise (Vue 3.5 / markRaw break virtual-scroll) rested on the same false automation signal and would mislead future decisions. The Vue pin it justified is addressed separately.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Issues closed by this merge
#46, #17, #1, #55, #53, #57, #68, #61, #70
Known gaps (not in this release)
#62 (delta-level cost clamping beyond ±4), #43 (separate player-XP-award figure), #25 (dark mode), #52/#51 (save/share encounters), #18 (random creature filter).
Before merging
mainstill carries the v1 code (GPLv3 LICENSE.md, semantic-release, umami analytics) that this branch does not have — needs reconciling (port LICENSE.md, decide on semantic-release/analytics) before or as part of this merge.Test plan